#!/bin/perl

########################################################
# Title : gIRC-Bot
# Description : IRC Bot with modular definition to 
# easily add interaction on chan. Allow specific command 
# with message like /me
# Date : Aug 2012
# Version : 0.1
# Dev : @titom
########################################################

########################################################
# @titom : 
# TODO : 
#	- Send to process
#	- Recording Functions (record links and/or specific items)
#
# FIXME :
#	- Regexp is exactly match on 1 time for 3 tries [FIXED cf modules_search() ] 
#	- said_msg() : Switcher with direct conf value without variable
#	- Bot Name is not used whith /whois command
#	- If we used sentence like "botNick blabla", message body is only "blablah"
########################################################


## Load Perl Module for Conf Reading / Switch Case and BasicBot
use strict;
use warnings;
use Switch;
use Config::IniFiles;
use Bot::BasicBot;
package MyBot;
use base qw( Bot::BasicBot );

## Constant value
## Modify at your own risk
use constant false => 0;
use constant true  => 1;
use constant DEBUG => 0; ## Only allow 0(disable) or 1(enable)

########################################################
#	Definitions
########################################################

## Config File
our $cfg = Config::IniFiles->new (
	-file => "./bot-config.cfg"
);

## Dialog Definition load from config file
my %modules;

## IRC Bot with paramters lod from config file
our $bot;

########################################################
#	Fonctions about configuration
########################################################

## Display DEBUG information if debug=1
sub debug {
	my ($fct,$msg)=@_;
	if(DEBUG) {
		print "**DEBUG - fonction : $fct - $msg\n";
	}
}

## Display Values from Associative Array
## Debug Purpose Only
sub dialog_display {
	my %dial = @_;
	if(DEBUG != 1) {
		return;
	}
	my $k;
	my $v;
	while (($k,$v) = each(%dial))
	{
		print "* Keyword : $k - Reply : $v\n";
	}
	
}

## Display all loaded commands
## Debug Purpose Only
sub commands_display {
	my (@commands)=@_;
	if(DEBUG) {
		foreach my $entry (@commands) {
			print "* Command loaded : $entry\n";
		}
	}
}

## Add Value to our Associative Array
sub module_add {
	my (%dest,%src)=@_;
	my ($k,$v)="0";
	while (($k, $v) = each(%src))
	{
		$dest{$k}=$v;
	}
	return %dest;
}

## Read Dialog and regexp value from configuration file
sub module_load_entity {
	my ($conf,$id) = @_;
	my %val;
	## Check if Module Exist
	if( $conf->exists($id,"exp") &&  $conf->exists($id,"reply") ) {
		## If yes, then get values and add it to an associative array
		$val{$conf->val($id,"exp")} = $conf->val($id,"reply");
		## Return it
		return %val;
	}
	## Otherwise return 0
	else { return false; }

}

## Find Value in configuration File
sub conf_get_value {
	## Get position and key to search
	my ($section,$id)=@_;
	## Check if value exist
	if( $cfg->exists($section,$id)){
		## If yes, then return it
		return $cfg->val($section,$id);
	}
	else {
		## Otherwise return 0
		return false;
	}
}

sub entities_load {
	my ($search)= @_;
	my %dialog;
	## Load All Regexp to search
	my $section="";
	## Go through all Sections defined in Configuration file
	foreach $section ($cfg->Sections()){
		if( $section =~ /$search/i ) {
			## If it is a Module Section
			print "* Load : $section\n";
			## Get key and value
			my %val1 = &module_load_entity($cfg,$section);
			## Add it to the array
			%dialog = &module_add(%dialog,%val1);
		}
	}
	return %dialog;
}

## Load Modules define in configuration file.
sub modules_load {
	my $search = &conf_get_value("general","module");
	my %mod = &entities_load($search);
	return %mod;
}

## Search if Someone said Keyword on the chan
sub modules_search {
	my ($msg) = @_;
	## Load sequentially one module
	foreach my $k (keys %modules)
	{
		## If message contains KEY
		if($msg =~ m/$k/i) {
			&debug("modules_search","Key match : $k");
			return $k;
		}
	}
	## If nothing match, we return nothing
	return false;
}

## Load all Commands describe in our configuration file
sub commands_load_keys {
	my @array = ();
	## Load Manually Keyword from configuration file
	push(@array,&conf_get_value("keys","emote"));
	push(@array,&conf_get_value("keys","say"));
	push(@array,&conf_get_value("keys","quit"));
	push(@array,&conf_get_value("keys","fortune"));
	## Start to load keyword functions
	## ...

	## End of Keywords
	return @array;
}

########################################################
#	BOT Functions
########################################################

## Load Bot Paramters
sub bot_load {
	my ($config)=@_;
	
	my $robot= MyBot->new(
		server=>&conf_get_value("bot","server"),
		channels=>&conf_get_value("bot","channels"),
		nick=>&conf_get_value("bot","nick"),
		name=>&conf_get_value("bot","name"),
	);
	return $robot;
}

## Display Bot Informations (Serveur/chan/Nick)
sub bot_display_inf {
	my ($robot) = @_;
	print "########################################################\n";
	print "# Nick : $bot->{nick}\n";
	print "# Name : $bot->{name}\n";
	print "# Server : ".$bot->{server}."\n";
	print "# Channel : ".$bot->{channels}[0]."\n";
	print "########################################################\n";

}

########################################################
#	BasicBot Functions Override
########################################################

## Help Function
sub help { 
	&conf_get_value("messages","help");
}

## Used to say something when someone Leave the chan
sub chanpart {
	my ($self,$message) = @_;
	return &conf_get_value("messages","quit");
}

## Used to say something when someone join the chan
sub chanjoin {
	my ($self, $message) = @_;
	if( $message->{who} =~ m/$bot->{nick}/ ) {
		## Message send to chan when BOT join it
		return &conf_get_value("messages","join-me");
	}
	else  {
		## Message send to chan weh someone join chan
		return &conf_get_value("messages","join");
	}
}

## Used to parse private message receive
sub said_msg {
	my ($self, $message) = @_;
	my $chan = $bot->{channels}[0];
	my $reply = "";

	## Received message
	my $string = $message->{body};
	$string =~/^(\w+)\s(.*)/;
	## Msg to send
	my $msg = $2;
	## Key Rcv (user or action)
	my $rcv_key = $1;

	## Read all keyword
	## Need to be optimized to deliver directly value to our switch
	my @actions = &commands_load_keys();

	## Switch to select good action
	switch ($string) {
		## Change Bot state with EMOTE
		## Exactly like /me command
		case /^$actions[0]/i {
			$bot->emote(
				channel=>$chan,
				body=>$msg,
			);
			$reply = "Ok, I send /me $msg";
		}
		## Say something to someone to the chan
		## Need to check if a function could be helpfull (used 1 time in this script)
		case /^$actions[1]\b/i {
			$message->{channel} = &conf_get_value("bot","channels");
			$msg =~m/(\w+)\s(.*)/i;
			$message->{who} = $1;
			$reply = "$2";
		}
		## Shutdown the nick
		case /^$actions[2]\b/i {
			## Leave IRC Serveur
			$bot->shutdown("Leaving");
			## Close Script
			exit 0;
		}
		## Display fortune on CHAN
		case /^$actions[3]\b/i {
			$msg =~m/(\w+)\s(.*)/i;
			$message->{channel} = &conf_get_value("bot","channels");
			$message->{who} = $2;
			my @fortune = `/usr/games/fortune`;
			$reply = join(" ",@fortune);
		}
		
		## Start to add more specific function managed by the bot
		## Could be Google Search / System information / Twitter / ...
		## ...	
		
		## End of custom functions

		## Default Reply when message is not parse correctly
		else {
			$reply=&conf_get_value("messages","unknown-msg");
		}
	}
	## Send Answer to msg window
	return $reply;
}

## Used to parse chan messages and send reply to it
sub said_chan {
	my ($self, $message) = @_;
	my $keyword = false;

	## Search Key in message
	&debug("said_chan","Message is :$message->{body}");
	$keyword = &modules_search($message->{body});
	&debug("said_chan","Found Key : $keyword");

	## If Key is found, then reply sentence define for the key
	if ($keyword) {
		return $modules{$keyword};
	}
}

## Main function wich receive messages (private and chan)
sub said {
	my ($self, $message) = @_;
	if( $message->{channel} =~ m/msg/i) {
		## Reply after private message
		&said_msg($self,$message);
	}
	else {
		&debug("said","Receive Chan Message");
		## Send Message to the Chan
		&said_chan($self,$message);
	}
}


########################################################
#	MAIN PART OF SCRIPT
########################################################

## Define Bot
$bot = &bot_load($cfg);
&bot_display_inf($bot);

## Load Modules
%modules = &modules_load();
&dialog_display(%modules);

## Run our Bot
$bot->run();
